package org.spring.oss;

import software.amazon.awssdk.auth.credentials.AwsBasicCredentials;
import software.amazon.awssdk.auth.credentials.StaticCredentialsProvider;
import software.amazon.awssdk.core.sync.RequestBody;
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.s3.S3Client;
import software.amazon.awssdk.services.s3.model.*;
import software.amazon.awssdk.services.s3.presigner.S3Presigner;
import software.amazon.awssdk.services.s3.presigner.model.GetObjectPresignRequest;

import java.io.InputStream;
import java.net.URI;
import java.time.Duration;
import java.time.temporal.ChronoUnit;

public class S3Oss implements IOss{

    private S3Client getClient(){
        return S3Client.builder()
                .endpointOverride(URI.create(getConfig().getEndPoint()))
                .region(Region.AF_SOUTH_1)
                .credentialsProvider(StaticCredentialsProvider
                        .create(AwsBasicCredentials.create(getConfig().getAccessKey(), getConfig().getAccessSecretKey())))
                .forcePathStyle(true)
                .build();
    }
    public S3Oss(){

    }

    private OssConfig config;
    @Override
    public OssConfig getConfig() {
        return config;
    }

    @Override
    public void setConfig(OssConfig config) {
        this.config=config;
    }

    @Override
    public boolean uploadStream(String bucket, String name, String filename, InputStream inputStream, long size) {
        try(S3Client s3Client=getClient()) {
            PutObjectRequest putObjectRequest = PutObjectRequest.builder()
                    .bucket(bucket)
                    .key(encodeName(name))
                    .contentDisposition(String.format("attachment;filename=%s", filename))
                    .build();
            s3Client.putObject(putObjectRequest, RequestBody.fromInputStream(inputStream, size));
            return true;
        }
        catch(Exception e){
            throw new RuntimeException(e);
        }
    }

    @Override
    public String buildDownloadUrl(String bucket, String name, long validTime) {
        try(S3Presigner s3Presigner=S3Presigner.builder().region(Region.of(getConfig().getRegion())).build()) {
            GetObjectRequest getObjectRequest = GetObjectRequest.builder()
                    .bucket(bucket)
                    .key(encodeName(name))
                    .build();
            GetObjectPresignRequest resignedGetObjectRequest = GetObjectPresignRequest.builder()
                    .signatureDuration(Duration.of(validTime, ChronoUnit.MINUTES))
                    .getObjectRequest(getObjectRequest).build();
            return s3Presigner.presignGetObject(resignedGetObjectRequest).url().toString();
        }
        catch (Exception e){
            throw new RuntimeException(e);
        }
    }

    @Override
    public boolean bucketExists(String bucket) {
        try(S3Client s3Client=getClient()){
            HeadBucketResponse response= s3Client.headBucket(HeadBucketRequest.builder().bucket(bucket).build());
            return response!=null;
        }
        catch (S3Exception e){
            if (e.statusCode()==404){
                return false;
            }
            throw new RuntimeException(e);
        }
        catch (Exception e){
            throw new RuntimeException(e);
        }
    }

    @Override
    public boolean objectExists(String bucket, String name) {
        try(S3Client s3Client=getClient()){
            HeadObjectResponse response= s3Client.headObject(HeadObjectRequest.builder()
                    .bucket(bucket).key(encodeName(name)).build());
            return response!=null;
        }
        catch (S3Exception e){
            if (e.statusCode()==404){
                return false;
            }
            throw new RuntimeException(e);
        }
        catch (Exception e){
            throw new RuntimeException(e);
        }
    }

    @Override
    public boolean deleteObject(String bucket, String name) {
        try(S3Client s3Client=getClient()){
            DeleteObjectResponse response= s3Client.deleteObject(DeleteObjectRequest.builder()
                    .bucket(bucket).key(encodeName(name)).build());
            return response!=null;
        }
        catch (S3Exception e){
            if (e.statusCode()==404){
                return true;
            }
            throw new RuntimeException(e);
        }
        catch (Exception e){
            throw new RuntimeException(e);
        }
    }


}
